﻿using System;
using System.Data;

namespace Datos
{
    public abstract class Datos : IDatos
    {
        #region Atributos

        protected IDbConnection _connection;
        protected IDbCommand _command;
        protected IDbTransaction _tx;
        protected int _txAbiertas;

        #endregion

        #region Propiedades

        public abstract string ConnectionString { get; set; }
        public bool TransaccionAbierta
        {
            get
            {
               return _txAbiertas > 0 ?  true : false;
            }
        }

        #endregion

        #region Metodos de conexion

        protected abstract IDbConnection CrearConnection();

        protected void AbrirConexion()
        {
            if (_connection == null)
            {
                _connection =  CrearConnection();
                _command = _connection.CreateCommand();
                _connection.Open();
            }
        }

        protected void CerrarConexion()
        {
            if (_txAbiertas == 0)
            {
                _connection.Close();
                _connection = null;
                _command = null;
                _tx = null;
            }
        }


        #endregion

        #region Metodos de transaccion

        public void TxBegin()
        {
            if (_txAbiertas == 0)
            {
                AbrirConexion();
                _tx = _connection.BeginTransaction();
                _command.Transaction = _tx;
                _txAbiertas = 1;
            }
            else
            {
                _txAbiertas++;
            }
        }

        public void TxCommit()
        {
            if (_txAbiertas == 1)
            {
                _tx.Commit();
                _txAbiertas = 0;
                CerrarConexion();
            }
            else
            {
                _txAbiertas--;
            }
        }
        public void TxRollback()
        {
            if (_txAbiertas == 1)
            {
                _tx.Rollback();
                _txAbiertas = 0;
                CerrarConexion();
            }
            else
            {
                _txAbiertas--;
            }
        }

        #endregion

        #region Metodos para enviar y obtener datos

        public int EnviarDatos(string spNombre, ref object[] parametros)
        {
            int FilasAfectadas = 0;
            _command.CommandType = CommandType.StoredProcedure;
            _command.CommandText = spNombre;
            _command.Parameters.Clear();
            CargarParametros(parametros, _command);
            try
            {
                FilasAfectadas = _command.ExecuteNonQuery();
            }
            catch (SystemException ex)
            {
                Console.WriteLine( ex.Message);
            }
            return FilasAfectadas;
        }


        /// <summary>
        /// Obtiene datos desde la Base de Datos
        /// </summary>
        public IDataReader ObtenerDataReader(string spNonmbre, object[] parametros)
        {
            IDbConnection conn;
            CommandBehavior behavior;
            IDbCommand cmd;
            if (_connection != null && _connection.State == ConnectionState.Open)
            {
                conn = _connection;
                behavior = CommandBehavior.Default;
                cmd = conn.CreateCommand();
                if (_txAbiertas >= 1) cmd.Transaction = _tx;
            }
            else
            {
                conn =  CrearConnection();
                behavior = CommandBehavior.CloseConnection;
                cmd = conn.CreateCommand();
                conn.Open();
            }
            cmd.CommandText = spNonmbre;
            cmd.CommandType = CommandType.StoredProcedure;
            CargarParametros(parametros, cmd);
            return cmd.ExecuteReader(behavior);
        }

        protected abstract void CargarParametros(object[] parametros, IDbCommand command);

        #endregion

    }
}
